package com.fqj.myexcels.service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service("distributeSerNumBiz")
public class DistributeSerNumService {
    @Resource
    private RedisService redisService;

    //用户编码当前最大值，存储在redis中的key
    private static final String CURRENT_MAX_USER_CODE_KEY = "CURRENT_MAX_USER_CODE_KEY";
    //用户编码前缀
//    private final static String PRE_GROUP_CODE = "w";
    private static String PRE_GROUP_CODE = "";
    //用户编码初始值，格式：前缀+8000000开始的流水，如：w8000001
//    private static final String INIT_USER_CODE = PRE_GROUP_CODE+"0000000";
    //默认前缀+流水"0000000"开始 如果前缀为空就默认用yyyyMMdd前缀
    private static String INIT_USER_CODE = PRE_GROUP_CODE+"0000000";

    //分布式锁的锁定时长，单位秒
    private static final int LOCK_TIME = 5;
    //分布式锁的key
    private static final String LOCK_KEY = "USER_CODE_INC_LOCK";

    //缓存初始化
    @PostConstruct
    public void initCurrentMaxUserCode(){
        //初始化获取数据库中最大编码值
        String currentMaxUserCode = (String)redisService.get(CURRENT_MAX_USER_CODE_KEY);

        //如果为空，则设置为初始值
        if(StringUtils.isBlank(currentMaxUserCode)){
            //不用年月日前缀把这行代码注释掉
            resetDateStr();
            currentMaxUserCode = INIT_USER_CODE;
            redisService.set(CURRENT_MAX_USER_CODE_KEY, currentMaxUserCode);
        }else{
            SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
            String redisTodyDayStr=currentMaxUserCode.substring(0,8);
            String todayStr=sdf.format(new Date());
            if(!redisTodyDayStr.equals(todayStr)){
                currentMaxUserCode=todayStr+currentMaxUserCode.substring(8);
                redisService.set(CURRENT_MAX_USER_CODE_KEY, currentMaxUserCode);
            }
        }


    }
    /**
     * 重置天到静态变量前缀
     */
    public void resetDateStr(){
        SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
        String todayStr=sdf.format(new Date());
        //为空 先把今天赋值给前缀静态变量
        if(StringUtils.isBlank(PRE_GROUP_CODE)){
            PRE_GROUP_CODE=todayStr;
            INIT_USER_CODE=PRE_GROUP_CODE+"0000000";

        }else{
            //如果变天了 静态变量重新赋值
            if(!todayStr.equals(PRE_GROUP_CODE)){
                PRE_GROUP_CODE=todayStr;
                INIT_USER_CODE=PRE_GROUP_CODE+"0000000";
                redisService.set(CURRENT_MAX_USER_CODE_KEY,INIT_USER_CODE);
            }
        }


    }

    /**
     * @Author  javaloveiphone
     * @Date 创建时间：2017年4月8日
     * @Description :获取最大编码值，当前服务被部署多套，采用：synchronized+redis分布式锁 形式共同完成
     * @param timeOut 循环获取最大值超时时长
     * @param timeUnit 超时单位
     * @return
     * String
     */
    public synchronized String getNewMax(long timeOut, TimeUnit timeUnit){
        String newMaxValue = null;
        if(timeUnit == null){
            timeUnit = TimeUnit.SECONDS;
        }
        long start = System.nanoTime();
        do{
            String lockValue = String.valueOf(new Date().getTime());
            int lockFlag = redisService.setnx(LOCK_KEY, lockValue).intValue();
            //判断是否有变天
            resetDateStr();
            //获取锁
            if(lockFlag==1){

                //1、设置有效期，防止当前锁异常或崩溃导致锁释放失败
                redisService.expire(LOCK_KEY, LOCK_TIME);

                //2、获取当前最大编码值
                String currentMaxValue = (String)redisService.get(CURRENT_MAX_USER_CODE_KEY);
                //如果redis中该值丢失，重新执行初始化
                if(StringUtils.isBlank(currentMaxValue)){
                    initCurrentMaxUserCode();
                    currentMaxValue = (String)redisService.get(CURRENT_MAX_USER_CODE_KEY);
                }

                //3、将最大值加1，获取新的最大值
//                int currentMaxNum = Integer.parseInt(currentMaxValue.substring(currentMaxValue.indexOf(PRE_GROUP_CODE)+1));
                int currentMaxNum = Integer.parseInt(currentMaxValue.substring(PRE_GROUP_CODE.length()+1));

                String currentMaxNumStr = String.format("%07d", currentMaxNum+1);
                newMaxValue = PRE_GROUP_CODE + currentMaxNumStr;

                //4、将新的最大值同步到redis缓存
                redisService.set(CURRENT_MAX_USER_CODE_KEY, newMaxValue);

                //5、释放锁，redis执行删除方法
                redisService.delete(LOCK_KEY);

                break;
                //未获取锁
            }else if(lockFlag==0){
                System.out.println(Thread.currentThread().getName()+"=====未获取锁,未超时将进入循环");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //如果未超时，则循环获取锁
        }while(System.nanoTime()-start<timeUnit.toNanos(timeOut));

        return newMaxValue;
    }




    public void getMaxUserCode(){
        for(int i=0;i<10;i++){
            Thread t = new Thread(){
                @Override
                public void run() {
                    System.err.println("start######################################################");
                    System.err.println(getNewMax(5, TimeUnit.SECONDS));
                    System.err.println("end########################################################");
                }
            };
            t.setName("线程"+i);
            t.start();
        }
        while (true){

        }
    }
}
